package mapEditor.map;

import debug.*;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Dimension;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.net.URL;

import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JOptionPane;

import org.json.JSONException;

import mapEditor.MapEditor;
import mapEditor.interactor.EditInteractor;
import mapEditor.interactor.DrawEllipseInteractor;
import mapEditor.interactor.DrawLineInteractor;
import mapEditor.interactor.Interactor;
import mapEditor.interactor.MeasureInteractor;
import mapEditor.interactor.DrawParallelogramInteractor;
import mapEditor.interactor.DrawPathInteractor;
import mapEditor.interactor.DrawPolygonInteractor;
import mapEditor.interactor.DrawTextInteractor;
import mapEditor.obj.DrawObject;
import mapEditor.utils.MapLocation;
import mapEditor.utils.Util;


public class MapCanvas extends JPanel implements Printable
{ static final long serialVersionUID=0; // AD'HOC
  private static final String TAG="mapEditor.map.MapCanvas";
//  private static final boolean VERBOSE=true;
  private static final boolean DEBUG=true;

  private ObjectModel objectModel;
  public ObjectModel getObjectModel() { return(objectModel); }
  public String getName() {return((objectModel==null)?"UNKNOWN":objectModel.getName()); }

  private JScrollPane scrollPane;
  
  private boolean showMapImage=true;
  private boolean showObjects=true;
  private boolean showGrid=true;
	  
  public void setShowMapImage(boolean on) { showMapImage=on; repaint(); }
  public void showObjectsAction(boolean on) { showObjects=on; repaint(); }
  public void setShowGrid(boolean on) { showGrid=on; repaint(); }
  
  private Interactor mapInteractor;
  private DrawObject.PointMark[] selectedPointMarks;
  
  private MapCanvas() {} // NOTE: PRIVATE CONSTRUCTOR

  // ******************************************************************
  // *** STATIC: createMapCanvas
  // ******************************************************************
  public static MapCanvas createMapCanvas(String name,URL backgroundImageUrl) throws IOException,JSONException
  { MapCanvas mapCanvas=new MapCanvas();
    mapCanvas.objectModel=new ObjectModel(name,mapCanvas,backgroundImageUrl);
    name=mapCanvas.objectModel.getName();
    mapCanvas.requestResize();
    mapCanvas.setInteractorAdapter(Interactor.MEASURE);
    mapCanvas.setSelected();
	return(mapCanvas);
  }

  // ******************************************************************
  // *** STATIC: openMapCanvas
  // ******************************************************************
  public static MapCanvas openMapCanvas(String name,Reader reader) throws IOException,JSONException
  { MapCanvas mapCanvas=new MapCanvas();
    mapCanvas.objectModel=new ObjectModel(name,mapCanvas,reader); // Read JSON Document
    name=mapCanvas.objectModel.getName();
    mapCanvas.requestResize();
    mapCanvas.setInteractorAdapter(Interactor.MEASURE);
    mapCanvas.setSelected();
	return(mapCanvas);
  }

  
  // ******************************************************************
  // *** METHOD: setInteractorAdapter
  // ******************************************************************
  public void setInteractorAdapter(int mouseMode)
  { Interactor a=null;
    switch(mouseMode)
    { case Interactor.MEASURE:        a=new MeasureInteractor(this);   break;
      case Interactor.EDIT:           a=new EditInteractor(this);      break; 
      case Interactor.DRAW_LINE:      a=new DrawLineInteractor(this);      break;
      case Interactor.DRAW_POLYGON:   a=new DrawPolygonInteractor(this);   break;
      case Interactor.DRAW_ELLIPSE:   a=new DrawEllipseInteractor(this);   break;
      case Interactor.DRAW_PARALLELOGRAM: a=new DrawParallelogramInteractor(this); break;
      case Interactor.DRAW_PATH:      a=new DrawPathInteractor(this);      break;
      case Interactor.DRAW_TEXT:      a=new DrawTextInteractor(this);      break;
    }
    setInteractorAdapter(a);
    MapEditor.getStatusLine().setMode(mapInteractor.getMouseModeMnemonic());
  }
  
  // ******************************************************************
  // *** METHOD: setInteractorAdapter
  // ******************************************************************
  private void setInteractorAdapter(Interactor newInteractor)
  { if(mapInteractor!=null)
    { this.removeKeyListener(mapInteractor);
	  this.removeMouseListener(mapInteractor);
	  this.removeMouseMotionListener(mapInteractor);
    }
    this.addKeyListener(newInteractor);
    this.addMouseListener(newInteractor);
    this.addMouseMotionListener(newInteractor);
    this.mapInteractor=newInteractor;  
  }
    
  // ******************************************************************
  // *** METHOD: getInteractorAdapter
  // ******************************************************************
  public Interactor getInteractorAdapter() { return(mapInteractor); }

  // ******************************************************************
  // *** METHOD: setSelected
  // ******************************************************************
  public void setSelected(DrawObject selected)
  { selectedPointMarks=(selected==null)?null:selected.getPointMarks();
    MapEditor.getSelectedTable().setSelected(selected);
    repaint();
  }

  // ******************************************************************
  // *** METHOD: zoom
  // ******************************************************************
  public void zoom(boolean in) { objectModel.zoom(in); requestResize(); }
  public void zoomReset() { objectModel.zoomReset(); requestResize(); }
  
  // *************************************************************************
  // *** METHOD: writeJSONFile
  // *************************************************************************
  public void writeJSONFile(Writer writer) throws JSONException
  { objectModel.writeJSONFile(writer); }

  public void setScrollPane(JScrollPane scrollPane)
  {	if(DEBUG) Log.d(TAG,"setScrollPane: "+scrollPane);
	this.scrollPane=scrollPane;
  }
  
  public void requestResize()
  {	int newWidth=(int)(objectModel.getCanvasWidth());
    int newHeight=(int)(objectModel.getCanvasHeight());
	if(DEBUG) Log.d(TAG,"requestResize: new Width="+newWidth+", new Height="+newHeight);
	setPreferredSize(new Dimension(newWidth,newHeight));
	
//    if(scrollPane!=null) scrollPane.reset(); // TODO: ????????
	if(scrollPane!=null) scrollPane.repaint();
    
  }
  
  public DrawObject getObject(MapLocation p)
  { return(objectModel.getObject(p)); }
  
  public DrawObject.PointMark getPointMark(MapLocation p)
  { if(selectedPointMarks==null) return(null);
    if(selectedPointMarks.length==0) return(null);
    double x=p.getX();
    double y=p.getY();
	for(int i=0;i<selectedPointMarks.length;i++)
    { double xL=selectedPointMarks[i].getMapLocation().getX()-5;
      double xH=xL+10;//marks[i].getX()+5;
      double yL=selectedPointMarks[i].getMapLocation().getY()-5;
      double yH=yL+10;//marks[i].getY()+5;
//      boolean inXrange=( xL<=x ) && ( x<=xH);
//      if(DEBUG) Log.d(TAG,"Check PointMark "+i+": xL="+xL+", x="+x+" ,xH="+xH+", inXrange="+inXrange);
	  if( ( xL<=x ) && ( x<=xH) && ( yL<=y ) && ( y<=yH) ) return(selectedPointMarks[i]);
    }
	return(null);  
  }
//
//  public void measurementDone(MapLocation loc1,MapLocation loc2)
//  { double dist=Util.round(loc1.getDistanceInMeter(loc2),100);
//    if(dist>0.1) JOptionPane.showMessageDialog(null,"DISTANCE: "+dist+" meter");
//  }
//
//  public void drawObjectDone(DrawObject obj,String id)
//  { int result=JOptionPane.showConfirmDialog(null,"DRAW "+id+": DONE\n Edit Attributes ?"
//      		  ,"Add "+obj.getClassName(),JOptionPane.YES_NO_OPTION);
//    if(result==JOptionPane.YES_OPTION) obj.edit();
//  }

  // *************************************************************************
  // *** METHOD: setSelected
  // *************************************************************************
  /**
  * Set this MapCanvas as selected among the tabed ones.
  **/
  public void setSelected()
  { int mouseMode=mapInteractor.getMouseMode();
    MapEditor.getControlPanel().setMouseMode(mouseMode);
    String mouseModeMnemonic=mapInteractor.getMouseModeMnemonic();
    MapEditor.getStatusLine().setMode(mouseModeMnemonic);
  }

  // *************************************************************************
  // *** METHOD: paint
  // *************************************************************************
  public void paint(Graphics g)
  { super.paint(g); // Clear panel
	if(showMapImage) objectModel.paintBackground((Graphics2D)g,this);
    if(showObjects) objectModel.paint((Graphics2D)g,this);
    if(mapInteractor!=null) mapInteractor.paintMouseEffect((Graphics2D)g,this); 
	if(showGrid) objectModel.paintGrid((Graphics2D)g,this);
    if(selectedPointMarks!=null)
  	{ for(int i=0;i<selectedPointMarks.length;i++)
  	  selectedPointMarks[i].paint((Graphics2D)g);
  	}
  }

  // *************************************************************************
  // *** METHOD: print
  // *************************************************************************
  public int print(Graphics g,PageFormat pageFormat,int pageIndex) throws PrinterException
  { paint(g);
	if(pageIndex==0) return(Printable.PAGE_EXISTS); 
	return(Printable.NO_SUCH_PAGE); 
  }

  public int getOrientation()
//  { return((getMapGrid().getCanvasWidth()>getMapGrid().getCanvasHeight())?PageFormat.LANDSCAPE:PageFormat.PORTRAIT);
  { return((getWidth()>getHeight())?PageFormat.LANDSCAPE:PageFormat.PORTRAIT);
  }

}
